//===============================================================================
// Microsoft Architecture Strategy Team
// LitwareHR - SaaS Sample Application
//===============================================================================
// Copyright  Microsoft Corporation.  All rights reserved.
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT
// LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE.
//===============================================================================
// The example companies, organizations, products, domain names,
// e-mail addresses, logos, people, places, and events depicted
// herein are fictitious.  No association with any real company,
// organization, product, domain name, email address, logo, person,
// places, or events is intended or should be inferred.
//===============================================================================


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Shp.Runtime.Contract;
using Shp.Runtime.Common;
using Shp.Runtime.Sitka.ServiceAgent;
using Shp.Runtime.Sitka.ServiceAgent.Entities;
using System.Globalization;
using Shp.Runtime.DataModel.Sitka.Constants;
using Shp.Runtime.DataModel.Sitka.Properties;
using Shp.Runtime.Sitka.ServiceAgent.Managers;

namespace Shp.Runtime.DataModel.Sitka
{
    public class PresentationDataModel
    {
        private IRepositoryFactory repositoryFactory;

        public PresentationDataModel(IRepositoryFactory factory)
        {
            repositoryFactory = factory;
        }

        public PresentationDataModel()
        {
            repositoryFactory = new GenericRepositoryFactory();
        }

        public int GetConfiguredLayout(string tenantAlias)
        {
            int resultLayout=0;
            SystemDataModel tenantAccess = new SystemDataModel(repositoryFactory);
            Guid tenantId = tenantAccess.GetTenantId(tenantAlias);
            if (tenantId.Equals(Guid.Empty))
            {
                throw new InvalidOperationException("Tenant Alias not exists.");
            }
            using (Repository<GenericExtensibleEntity> repository = repositoryFactory.MetadataRepository)
            {
                GenericExtensibleEntity tenant = repository.GetById(tenantId);

                if (!int.TryParse(tenant.GetFieldValue("Layout"),out resultLayout))
                {
                    throw new InvalidCastException("Layout cannot be converted to Int");
                }
            }

            return resultLayout;
        }

        public Guid GetCurrentStyleId(Guid tenantId)
        {
            Guid resultStyle = Guid.Empty;
            using (Repository<GenericExtensibleEntity> repository = repositoryFactory.MetadataRepository)
            {
                GenericExtensibleEntity tenant = repository.GetById(tenantId);

                resultStyle = new Guid(tenant.GetFieldValue("Style"));
            }

            return resultStyle;
        }

        public string GetConfiguredStyle(string tenantAlias)
        {
            string resultStyle = string.Empty;
            Guid styleId = Guid.Empty;
            SystemDataModel tenantAccess = new SystemDataModel(repositoryFactory);
            Guid tenantId = tenantAccess.GetTenantId(tenantAlias);
            if (tenantId.Equals(Guid.Empty))
            {
                throw new InvalidOperationException("Tenant Alias not exists.");
            }
            styleId = GetCurrentStyleId(tenantId);

            using (Repository<GenericExtensibleEntity> repository = repositoryFactory.MetadataRepository)
            {
                GenericExtensibleEntity style = repository.GetById(styleId);
                resultStyle = style.GetFieldValue("Url");
            }

            return resultStyle;
        }

        public StringPair[] GetMainMenu(string tenantAlias, bool isPublic)
        {
            List<StringPair> resultMenuList = new List<StringPair>();
            SystemDataModel tenantAccess = new SystemDataModel(repositoryFactory);
            Guid tenantId = tenantAccess.GetTenantId(tenantAlias);
            if (tenantId.Equals(Guid.Empty))
            {
                throw new InvalidOperationException("Tenant Alias not exists.");
            }

            using (Repository<GenericExtensibleEntity> repository = repositoryFactory.MetadataRepository)
            {
                //int isPublicParameter = (isPublic) ? 1 : 0;
                string isPublicParameter = isPublic.ToString().ToLowerInvariant();
                IEnumerable<GenericExtensibleEntity> mainMenuResult = repository.Search(string.Format(CultureInfo.InvariantCulture, SitkaPresentationQueries.GetMainMenuByTenantIdAndPublicity, tenantId.ToString(), isPublicParameter));
                foreach (GenericExtensibleEntity mainMenu in mainMenuResult)
                {
                    resultMenuList.Add(new StringPair(mainMenu.GetFieldValue("Description"), mainMenu.GetFieldValue("Url")));
                }
                bool existsDuplicated = resultMenuList.Exists(
                    menu => resultMenuList.Count(count => count.Key == menu.Key) > 1);

                if (existsDuplicated)
                {
                    // An incosistent view definition has been added directly to the db
                    // you should guard against this behaviour
                    throw new System.Security.SecurityException(Resources.InvalidConfigurationDuplicateKey);
                }
            }
            return resultMenuList.ToArray();
        }

        public KeyValuePair<Guid, string>[] GetStyleList(Guid tenantId)
        {
            List<KeyValuePair<Guid, string>> resultList=new List<KeyValuePair<Guid,string>>();
            using (Repository<GenericExtensibleEntity> repository = repositoryFactory.MetadataRepository)
            {
                IEnumerable<GenericExtensibleEntity> stylesResult = repository.Search(string.Format(CultureInfo.InvariantCulture, SitkaPresentationQueries.GetStyleByTenantId, tenantId.ToString()));
                List<GenericExtensibleEntity> genericList = new List<GenericExtensibleEntity>(stylesResult);
                resultList = genericList.ConvertAll(
                    style => new KeyValuePair<Guid, string>(style.Id, style.GetFieldValue("Name")));
            }
            return resultList.ToArray();
        }

        public void UpdatePresentation(Guid tenantId, int layout, Guid style)
        {
            using (Repository<GenericExtensibleEntity> repository = repositoryFactory.MetadataRepository)
            {
                GenericExtensibleEntity tenant = repository.GetById(tenantId);
                tenant.SetFieldValue("Layout", layout.ToString(CultureInfo.InvariantCulture));
                tenant.SetFieldValue("Style", style.ToString());

                repository.Update(tenant);
            }
        }

        public void AddStyle(Guid tenantId, string name, Uri url)
        {
            using (Repository<GenericExtensibleEntity> repository = repositoryFactory.MetadataRepository)
            {
                GenericExtensibleEntity style = new GenericExtensibleEntity("Style", Guid.NewGuid());
                style.SetFieldValue("TenantId", tenantId.ToString());
                style.SetFieldValue("Name", name);
                style.SetFieldValue("Url", url.ToString());

                repository.Insert(style);
            }
        }

        public MainMenuItem[] GetMainMenuList(Guid tenantId)
        {
            List<MainMenuItem> menuResult = new List<MainMenuItem>();
            using (Repository<GenericExtensibleEntity> repository = repositoryFactory.MetadataRepository)
            {
                IEnumerable<GenericExtensibleEntity> mainMenuResult = repository.Search(string.Format(CultureInfo.InvariantCulture, SitkaPresentationQueries.GetMainMenuByTenantId, tenantId.ToString()));
                foreach (GenericExtensibleEntity entity in mainMenuResult)
                {
                    MainMenuItem menu = new MainMenuItem();
                    menu.Description = entity.GetFieldValue("Description");
                    menu.Url = entity.GetFieldValue("Url");
                    menu.IsPublic = bool.Parse(entity.GetFieldValue("IsPublic"));

                    menuResult.Add(menu);
                }
            }
            return menuResult.ToArray();
        }

        public void UpdateMainMenu(Guid tenantId, MainMenuItem[] menuItems)
        {    
            List<MainMenuItem> menuList = new List<MainMenuItem>(menuItems);

            if (menuList.Exists(menu => menuList.Count(count => count.Description == menu.Description && count.IsPublic == menu.IsPublic) > 1))
            {
                throw new System.Security.SecurityException(Resources.InvalidConfigurationDuplicateKey);
            }

            using (Repository<GenericExtensibleEntity> repository = repositoryFactory.MetadataRepository)
            {
                IEnumerable<GenericExtensibleEntity> deletingMenu = repository.Search(string.Format(CultureInfo.InvariantCulture, SitkaPresentationQueries.GetMainMenuByTenantId, tenantId.ToString()));
                foreach (GenericExtensibleEntity delete in deletingMenu)
                {
                    repository.Delete(delete.Id);
                }

                int ordinal = 1;
                foreach (MainMenuItem newMenu in menuList)
                {
                    GenericExtensibleEntity newEntity = new GenericExtensibleEntity("MainMenu", Guid.NewGuid());
                    newEntity.SetFieldValue("TenantId",tenantId.ToString());
                    newEntity.SetFieldValue("Description",newMenu.Description);
                    newEntity.SetFieldValue("Url",newMenu.Url);
                    newEntity.SetFieldValue("IsPublic",newMenu.IsPublic.ToString(CultureInfo.InvariantCulture));
                    newEntity.SetFieldValue("Ordinal", ordinal.ToString(CultureInfo.InvariantCulture));

                    repository.Insert(newEntity);
                    ordinal++;
                }
            }
        }
    }
}
